// ----------------------------------------------------------------------------
// condition.h
// ----------------------------------------------------------------------------
/*
 Description:
 条件変数の実装.
 ミューテクスによる排他処理が入るので、荒い粒度の同期に利用すること.
 */
#pragma once
#include <fw/base/core/macros.h>
#include <fw/base/core/assertion.h>
#include <fw/base/core/noncopyable.h>

#include <fw/base/concurrent/mutex.h>

namespace fw
{
	struct SemaphoreObject;
	
	/**
	 * 条件変数の定義.
	 */
	class Condition : private NonCopyable
	{
	public:
		
		 Condition(const char* gatename, const char* queuename);
		
		~Condition();
		
		/**
		 * 待機している一つのスレッドへの起床通知.
		 * 待機しているスレッドが無い場合、なにも起こらない.
		 */
		void 							NotifyOne();
		
		/**
		 * 待機しているすべてのスレッドへの起床通知.
		 * 待機しているスレッドが無い場合、なにも起こらない.
		 */
		void 							NotifyAll();
		
		/**
		 * 起床されるまでの間、スレッドをブロックする.
		 * 
		 * @param _Locker [in]  スレッドのクリティカルセクションを実現するためのミューテクスロッカークラス.
		 * @param rLocker [in]  ミューテクスロッカーへの参照.
		 */
		template < typename _Locker >
		void						Wait( _Locker& locker )
		{
			FW_ASSERT( locker.IsLocked() );
			
			EnterWait();
			
			locker.Unlock();
			Wait();
			locker.Lock();
		}
		
	private:
		
		/**
		 * Wait関数の前に呼び出される関数.
		 */
		void 							EnterWait();
		
		/**
		 * ウェイトの実装.
		 */
		void 							Wait();
		
		SemaphoreObject*				m_gateSemaphore;
		
		SemaphoreObject*				m_queueSemaphore;
		
		/**
		 * 内部で利用するミューテクス. 
		 */
		Mutex							m_mutex;
		
		/**
		 * この条件変数によっていくつのスレッドをブロックしているか. 
		 */
		uint32_t 						m_blocked;
		
		/**
		 * この条件変数で待たされているスレッドのうち、
		 * 既にブロックされていないが Wait から抜け出ていないスレッドの数.
		 */
		uint32_t 						m_waiting;
		
		/**
		 * 名前無しの条件変数は作成できない. 
		 */
		Condition();
		
	}; /* class Condition */	
	
} // namespace fw
